feat(observations)!: dated events never collapse across dates (D106) - #360
Conversation
The observation adjudicator judged whether a new statement re-asserts an existing one from two bare strings, never reading the D41 event window every claim already carries. On LoCoMo conv-42 that folded three of seven dated tournament wins into earlier facts — October's "won a really big tournament last week" became evidence for January's "won his first tournament last week" because both say "last week" — and ten participation lineages collapsed into header boilerplate, swallowing two real entries. Add the deterministic temporal-compatibility rung D43's design named but never implemented: two dated events with disjoint resolved windows never interact and buy no verdict (also overriding the exact-statement shortcut); a dated event paired with an undated statement may still be judged for supersede/contradict, but an `evidence` verdict is coerced to `new` and recorded; undated pairs and overlapping-window events behave as before. The verdict prompt now shows both timelines. The candidate block derives each observation's event window from its supporting event-time claims. Roll the adjudicator generation, the adjudicate_observations flush component version, and the LoCoMo protocol (Full-v20 -> Full-v21). Add seven D106 fixture tests driven by a collapse-happy fake model, the D106 decision, the observations design amendment and worked example, the conv-42 evidence analysis, and the docs/status updates. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
…pping pairs (D106 review) Codex review of #360 found the first cut over-broad: disjoint dated events were declared unrelated without a verdict, which would double-count one occurrence whose date two sources dispute and suppress its contradiction group. Disjoint pairs now reach the date-aware model and may only contradict or stay new; evidence and supersede are coerced to new and recorded. The exact-statement shortcut requires temporal compatibility (identical text beside a dated/undated or disjoint-window twin coexists, decided without a model). Open-ended D41 windows stay unbounded instead of collapsing to a point. In-batch candidates carry timing on every insert and widen their windows as they absorb evidence. Every verdict record carries the coercions before it. The entity flush handler reports the claimed unit's own component generation to its barrier so units enqueued before the OBS_FLUSH_VERSION roll drain under the generation their barrier counts; D106 states the stop-drain-rebuild rollout. The verdict prompt labels each side's two clocks ("said on" — the source's date; "is about" — the resolved world-time of any D41 kind) and defines them. Six more proofs; stale v20-as-current references corrected. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
Independent review — Codex (
|
Review triage — dispositions applied in the follow-up commitEvery Codex finding was re-verified against the code before acting. The review changed the design materially (not just wording): the first revision treated disjoint dated events as never interacting; the shipped rule now bounds what a verdict may do and keeps the date-aware model in the loop.
Also folded in since the review ran: the verdict prompt now labels each side's two clocks explicitly ( Codex's verdict was "request changes"; all five majors are addressed by behavior changes with tests, not wording. Full suite, |
…ble fragments The operational-scale battery gates "one block read and one claim-timing read per entity batch" by matching literal SQL prefixes. D106 aliases the observations table and selects the D41 valid-time columns, so the old prefixes no longer occurred although both statements still run exactly once. Match stable fragments of the new statements instead; the counts and transaction gates are unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
Validation state at merge
|
Problem
The observation adjudicator (D43) decides whether a new entity-anchored statement re-asserts an existing one by sending the small model exactly two strings —
EXISTINGandNEW— with no dates, even though every claim carries a resolved D41 valid-time window (claim_valid_kind/claim_valid_from/claim_valid_until).On the v0.11.0 LoCoMo
conv-42run (plan/analysis/locomo_conv42_recurring_event_adjudication.md), extraction captured all seven of Nate's tournament wins as clean, dated claims and identity resolved one Nate — yet the fact layer kept four win facts. Theobservation_adjudicationstranscript shows the small model judged October's "won a really big video game tournament last week" to beevidencefor January's "won his first video game tournament last week" (both say "last week"), and folded the international and Valorant wins into "has been winning a few gaming tournaments". Ten participation lineages collapsed into the header boilerplate "Nate is a participant.", swallowing two real tournament entries. The counting question was answered "At least five" against seven.Change (decision D106)
A deterministic temporal-compatibility rung in
spine/observation_adjudication.pythat bounds what a verdict may do, using the D41 windows the claims already carry — the "deterministic value/period compare" step the D43 cascade always named but never implemented:contradict(both stand, grouped) or staynew;evidence/supersedeare coerced tonewand recorded. Byte-identical text is then kept apart without any model call;evidenceis coerced tonew— a specific dated event never re-asserts a vaguer summary, and a summary never re-asserts a specific event; identical text is kept apart without a model call;The verdict prompt shows, for each statement, when the source said it and what world-time it is about (the resolved window of any D41 kind), and defines both clocks.
_BLOCK_ENTITYderives each observation's windows from its supporting current-testimony claims; in-batch candidates carry timing on every insert and widen as they absorb evidence; every verdict record carries the coercions before it.Versions roll (provenance, D12):
OBSERVATION_ADJUDICATOR_VERSION→obs-adjudicator-2026.09a:temp0-1:temporal-gate-1;OBS_FLUSH_VERSION→e3-obs-flush-2026.09a:temporal-gate-1:claim-fanout-1:entity-fanout-1; LoCoMo protocol Full-v20 → Full-v21 (precedent: D100/D102/D104/D105). Rollout is stop-drain-rebuild: the entity flush handler now reports the claimed unit's own generation to its barrier, so units enqueued before the roll drain cleanly; readiness reports the old generation until rebuild.What is deliberately not changed
valid_fromstays the claim'sasserted_at; using the resolved window as the observation's own validity is a separate decision.Tests
Thirteen
test_d106_*proofs insrc/tests/spine/test_observation_adjudication.py, mostly driven by a collapse-happy fake model that answersevidencefor any tournament pair, so they pass only if the rung makes the model's answer irrelevant: seven dated wins → seven facts; arrival-order invariance; same-event re-mention still collapses; identical words about two dates → two events (no model); identical text dated-beside-undated coexists (no model); vague summary never absorbs a dated event (and the mirror), asserting the prompt'ssaid on/is aboutlines and the recorded coercion; boilerplate never absorbs dated participation; open window stays unbounded; year+day overlap may collapse; in-batch widening (one row, three evidence links, zero verdicts); disjoint dates may still contradict one occurrence (shared group); a dated event may supersede an undated state. Plus a rollout proof that the flush handler reports the claimed unit's generation. All existing D43/D88/D90 proofs unchanged and green.Validation:
ruff check,ruff format --check,pyrightclean repo-wide. Targeted suites (adjudicator, E3, protocol, runner) green. Full suite against the CI PostgreSQL image: 2,185 passed;test_client_sdk::test_sdk_pushes_lineage_metadata_to_e0also fails on unmodifiedmainin this environment (MIME detection); sixtest_query_space_batch_aproofs failed in the full run but pass alone and in sequence with the adjudication module on this branch — a full rerun with captured tracebacks is in progress and will be reported here before merge.Contributor agreement
Review
Codex (
gpt-5.6-sol, xhigh) review and triage are posted as comments; all five majors are addressed by behavior changes with tests. Antigravity could not run (account quota exhausted, resets in ~4 days).Corpus (same PR)
decisions.mdD106 (+ D78 banner) ·plan/designs/observations_design.md§3 rung + worked example ·plan/designs/locomo_benchmark_design.mdD106 amendment (D105 historical) ·plan/analysis/locomo_conv42_recurring_event_adjudication.md·plan/plans/phase-2-truth-machinery.mdWP-2.5 note ·benchmarks/locomo/README.mdV21 ·website/.../project-statusbullet.🤖 Generated with Claude Code
https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR